
#Область ОписаниеПеременных
	
&НаКлиенте
Перем УИ_ИдентификаторСтрокиДляРазворачивания; //Число, Неопределено	
	
&НаКлиенте
Перем УИ_ХранилищеДанныхФормы Экспорт;

#КонецОбласти

#Область ОбработчикиСобытийФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	УИ_ОбщегоНазначения.ФормаИнструментаПриСозданииНаСервере(ЭтотОбъект, Отказ, СтандартнаяОбработка);

	УстановитьУсловноеОформлениеДерева();

	Если Параметры.Свойство("КонтейнерЗначения") Тогда
		//@skip-check unknown-form-parameter-access
		ВходящееЗначениеКонтейнер = Параметры.КонтейнерЗначения;
		//@skip-check unknown-form-parameter-access
		КонтекстКлиента = Параметры.КонтекстКлиента;
		//@skip-check unknown-form-parameter-access
		Выражение = Параметры.Выражение;
		
		ЗначениеКонтейнера = УИ_ОбщегоНазначенияКлиентСервер.ЗначениеИзХранилищаКонтейнераУниверсальногоЗначения(ВходящееЗначениеКонтейнер);
		УстановитьЗначениеКорневойСтроки(ЭтотОбъект, ЗначениеКонтейнера);
		
		Элементы.ГруппаВыражение.ТолькоПросмотр = Истина;
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	КонтекстКлиента = УИ_ОбщегоНазначенияКлиентСервер.ТекущийКонтекстПлатформы();
	УИ_ХранилищеДанныхФормы = Новый Соответствие();

	
	Если ВходящееЗначениеКонтейнер <> Неопределено Тогда
		Возврат;
	КонецЕсли;

КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовШапкиФормы
&НаКлиенте
Процедура ВыражениеПриИзменении(Элемент)
	Если НаКлиенте Тогда
		ВычислитьВыражение(ЭтотОбъект);
	Иначе
		ВыражениеПриИзмененииНаСервере();
	КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормыДеревоЗначения
&НаКлиенте
Процедура ДеревоЗначенияПередРазворачиванием(Элемент, Строка, Отказ)
	
	СтрокаДерева = ДеревоЗначения.НайтиПоИдентификатору(Строка);
	Если СтрокаДерева = Неопределено Тогда
		Возврат;
	КонецЕсли;
	Если СтрокаДерева.ЗаполненыПотомки Тогда
		Возврат;
	КонецЕсли;
	
	УИ_ИдентификаторСтрокиДляРазворачивания = Строка;
	ПодключитьОбработчикОжидания("ЗаполнитьПотомковСтрокиОтложенно", 0.1, Истина);
	
КонецПроцедуры

&НаКлиенте
Процедура ДеревоЗначенияВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
	СтандартнаяОбработка = Ложь;
	
	ДанныеСтроки = ДеревоЗначения.НайтиПоИдентификатору(ВыбраннаяСтрока);
	Если ДанныеСтроки = Неопределено Тогда
		Возврат;
	КонецЕсли;	
	
	Если Поле.Имя = "ДеревоЗначенияЗначениеЕстьОшибка" И ДанныеСтроки.ЗначениеЕстьОшибка Тогда
		УИ_ОбщегоНазначенияКлиент.ОткрытьФормуРедактированияТекста(ДанныеСтроки.ЗначениеОписаниеОшибки,
																   УИ_ОбщегоНазначенияКлиент.НовыйПустоеОписаниеОповещения(),
																   "Ошибка при обработке свойства " + ДанныеСтроки.Имя,
																   ,
																   Истина);
	Иначе
		ПоказатьЗначениеВОтдельномОкне();
	КонецЕсли;
	
КонецПроцедуры
#КонецОбласти


#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура ПоказатьВОтдельномОкне(Команда)
	ПоказатьЗначениеВОтдельномОкне();
КонецПроцедуры

//@skip-check module-unused-method
&НаКлиенте
Процедура Подключаемый_ВыполнитьОбщуюКомандуИнструментов(Команда) 
	УИ_ОбщегоНазначенияКлиент.Подключаемый_ВыполнитьОбщуюКомандуИнструментов(ЭтотОбъект, Команда);
КонецПроцедуры


#КонецОбласти

#Область СлужебныеПроцедурыИФункции

&НаСервере
Процедура УстановитьУсловноеОформлениеДерева()
	УИ_ОбщегоНазначения.УстановитьУсловноеОформлениеТаблицыЗначенийПросмотраЗначений(ЭтотОбъект,
																					 Элементы.ДеревоЗначения,
																					 "ДеревоЗначения");

КонецПроцедуры

&НаКлиенте
Процедура ПоказатьЗначениеВОтдельномОкне()
	ТекущиеДанные = Элементы.ДеревоЗначения.ТекущиеДанные;
	Если ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ВидыКонтейнеров = ВидыКонтейнераЗначения();
	
	ХранилищеДляПараметровФормы = УИ_ОбщегоНазначенияКлиентСервер.НовыйХранилищеЗначенияУниверсальногоЗначения();
	ХранилищеДляПараметровФормы.ОписаниеТипа = ТекущиеДанные.ЗначениеТипЗначения;
	ХранилищеДляПараметровФормы.ИмяОбъектаМетаданных = ТекущиеДанные.ИмяОбъектаМетаданных;
	
	Если ТекущиеДанные.ВидКонтейнера = ВидыКонтейнеров.ВычислитьПоРодительскойСтроке Тогда
		СтрокаСвойства = ТекущиеДанные;
		НашлиЗначение = Ложь;
		Пока не НашлиЗначение Цикл
			ХранилищеДляПараметровФормы.ИменаСвойствДляДоступаКЗначению.Добавить(СтрокаСвойства.Имя);
			
			СтрокаСвойства = СтрокаСвойства.ПолучитьРодителя();
			Если СтрокаСвойства = Неопределено Тогда
				НашлиЗначение = Истина;
			КонецЕсли;
			Если СтрокаСвойства.ВидКонтейнера <> ВидыКонтейнеров.ВычислитьПоРодительскойСтроке Тогда
				НашлиЗначение = Истина;
				ХранилищеДляПараметровФормы.Вид = СтрокаСвойства.ВидКонтейнера;
				ХранилищеДляПараметровФормы.Хранилище = СтрокаСвойства.ЗначениеКонтейнер;
			КонецЕсли;

		КонецЦикла;
	ИначеЕсли ТекущиеДанные.ВидКонтейнера = ВидыКонтейнеров.ВычислитьВыражение Тогда
	ИначеЕсли ТекущиеДанные.ВидКонтейнера = ВидыКонтейнеров.ХранилищеДанныхФормы Тогда
		 
	Иначе
		ХранилищеДляПараметровФормы.Вид = ТекущиеДанные.ВидКонтейнера;
		ХранилищеДляПараметровФормы.Хранилище = ТекущиеДанные.ЗначениеКонтейнер;
	КонецЕсли;
	
	СтрокаВыражения = "";
	СтрокаСвойства = ТекущиеДанные;
	Пока СтрокаСвойства <> Неопределено Цикл
		СтрокаРодителяСвойства = СтрокаСвойства.ПолучитьРодителя();

		Если СтрокаРодителяСвойства <> Неопределено Тогда
			СтрокаВыражения = "." + СтрокаСвойства.Имя + СтрокаВыражения;
		КонецЕсли;

		СтрокаСвойства = СтрокаРодителяСвойства;
	КонецЦикла;

	УИ_ОбщегоНазначенияКлиент.ПросмотретьЗначение(ХранилищеДляПараметровФормы, ЭтотОбъект, Выражение + СтрокаВыражения);
	
КонецПроцедуры

&НаКлиенте
Процедура ЗаполнитьПотомковСтрокиОтложенно()
	Если УИ_ИдентификаторСтрокиДляРазворачивания = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ЗаполнитьПотомковСтроки(УИ_ИдентификаторСтрокиДляРазворачивания);
	
	УИ_ИдентификаторСтрокиДляРазворачивания = Неопределено;
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Функция ВидыКонтейнераЗначения() 
	Виды = УИ_ОбщегоНазначенияКлиентСервер.ВидыКонтейнераУниверсальногоЗначения();
	Виды.Вставить("ВычислитьПоРодительскойСтроке", "ВычислитьПоРодительскойСтроке");
	Виды.Вставить("ВычислитьВыражение", "ВычислитьВыражение");
	Виды.Вставить("ХранилищеДанныхФормы", "ХранилищеДанныхФормы");//Доступен только для клиента
	
	Возврат Виды;	
КонецФункции

&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеСтрокиДереваЗначения(Форма, СтрокаДерева)
	Если СтрокаДерева = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	
	ВидыКонтейнераЗначения = ВидыКонтейнераЗначения();

	Если СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.Значение Тогда
		Возврат СтрокаДерева.Значение;
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.ХранилищеЗначения Тогда
#Если Сервер Тогда
		Возврат СтрокаДерева.ЗначениеКонтейнер.Получить();
#КонецЕсли
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.ОбъектМетаданных Тогда
#Если Сервер Тогда
		Возврат Метаданные.НайтиПоПолномуИмени(СтрокаДерева.ИмяОбъектаМетаданных);
#КонецЕсли
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.ВременноеХранилище Тогда
		Возврат ПолучитьИзВременногоХранилища(СтрокаДерева.ЗначениеКонтейнер);
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.СериализованноеЗначение Тогда
		Возврат УИ_ОбщегоНазначения.ЗначениеИзСтрокиXML(СтрокаДерева.ЗначениеКонтейнер);
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.ВычислитьПоРодительскойСтроке Тогда
		ЗначениеИзСтрокиРодителя = ЗначениеСтрокиДереваЗначения(Форма, СтрокаДерева.ПолучитьРодителя());
		Возврат ЗначениеИзСтрокиРодителя[СтрокаДерева.Имя];
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.ВычислитьВыражение Тогда
		Попытка
#Если Не ТонкийКлиент И Не ВебКлиент Тогда
			УстановитьБезопасныйРежим(Истина);
#КонецЕсли
			//@skip-check server-execution-safe-mode
			Возврат Вычислить(СтрокаДерева.Имя);
		Исключение
			Возврат Неопределено;
		КонецПопытки;
	ИначеЕсли СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.СтруктураВоВременномХранилище Тогда
		СтруктураЗначения = ПолучитьИзВременногоХранилища(СтрокаДерева.ЗначениеКонтейнер);
		Если ТипЗнч(СтруктураЗначения) = Тип("Структура") Тогда
			Возврат СтруктураЗначения.Значение;
		Иначе
			Возврат Неопределено
		 КонецЕсли;
	КонецЕсли;
КонецФункции

&НаСервере
Процедура ЗаполнитьПотомковСтроки(ИдентификаторСтроки)
	СтрокаДерева = ДеревоЗначения.НайтиПоИдентификатору(ИдентификаторСтроки);
	Если СтрокаДерева = Неопределено Тогда
		ВозвраТ;
	КонецЕсли;
	Если СтрокаДерева.ЗаполненыПотомки Тогда
		Возврат;
	КонецЕсли;
	СтрокаДерева.ЗаполненыПотомки = Истина;
	ЗначениеСтрокиДерева = ЗначениеСтрокиДереваЗначения(ЭтотОбъект, СтрокаДерева);

	ЭлементыСтроки = СтрокаДерева.ПолучитьЭлементы();
	ЭлементыСтроки.Очистить();

	ОбъектМД = Метаданные.НайтиПоПолномуИмени(СтрокаДерева.ИмяОбъектаМетаданных);
	
	ОписаниеТипа = СтрокаДерева.ЗначениеТипЗначения;//см. УИ_ТипыПлатформыКлиентСервер.НовыйОписаниеТипаПлатформы
//	Если ОписаниеТипа.ЭтоКоллекция Тогда
//		Возврат;
//	КонецЕсли;
	
	ИменаСвойств = УИ_ОбщегоНазначения.ИменаСвойствОписанияТипаПлатформы(ОписаниеТипа, ЗначениеСтрокиДерева, ОбъектМД);
	
	Для Каждого ТекИмяСвойства Из ИменаСвойств Цикл
		СтрокаСвойстваДерева = ЭлементыСтроки.Добавить();
		СтрокаСвойстваДерева.Имя = ТекИмяСвойства;
		
		Попытка
			ЗначениеСвойства = ЗначениеСтрокиДерева[ТекИмяСвойства];
		Исключение
			СтрокаСвойстваДерева.ЗначениеЕстьОшибка = Истина;
			СтрокаСвойстваДерева.ЗначениеОписаниеОшибки = "Не удалось вычислить значение свойства: "+ОписаниеОшибки();
			Продолжить;
		КонецПопытки;
		
		УстановитьЗначениеВСтрокуДерева(ЭтотОбъект, СтрокаСвойстваДерева, ЗначениеСвойства, Ложь);
	КонецЦикла;
	
	
КонецПроцедуры

&НаСервере
Процедура ВыражениеПриИзмененииНаСервере()
	ВычислитьВыражение(ЭтотОбъект);
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Процедура УстановитьЗначениеКорневойСтроки(Форма, Значение)
	ЭлементыДерева = Форма.ДеревоЗначения.ПолучитьЭлементы();
	ЭлементыДерева.Очистить();
	
//	ОписаниеТипаЗначения = УИ_ТипыПлатформыКлиентСервер.ОписаниеТипаПлатформыПоТипу(ТипЗнч(Значение));
//	Если ОписаниеТипаЗначения = Неопределено Тогда
//		УИ_ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось получить описание типа значения.");
//		Значение = Неопределено;
//		Возврат;
//	КонецЕсли;
	
	КорневаяСтрока = ЭлементыДерева.Добавить();
	КорневаяСтрока.Имя = Форма.Выражение;

	УстановитьЗначениеВСтрокуДерева(Форма, КорневаяСтрока, Значение, Истина, Истина);
	
	Форма.Элементы.ДеревоЗначения.ТекущаяСтрока = КорневаяСтрока.ПолучитьИдентификатор();
	
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Процедура ВычислитьВыражение(Форма)
	
#Если Не ТонкийКлиент И Не ВебКлиент Тогда
//	УстановитьБезопасныйРежим(Истина);
#КонецЕсли
	Попытка
		//@skip-check server-execution-safe-mode
		Значение = Вычислить(Форма.Выражение);
	Исключение
		УИ_ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ОписаниеОшибки());
		Возврат;
	КонецПопытки;
	
	 УстановитьЗначениеКорневойСтроки(Форма, Значение);
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Процедура УстановитьЗначениеВСтрокуДерева(Форма, СтрокаДерева, Значение, УстанавливатьЗначениеКонтейнера,
	Очистить = Ложь)
	
	УИ_ОбщегоНазначенияКлиентСервер.УстановитьЗначениеВЭлементыФормыКонтейнераУниверсальногоЗначения(Форма,
																									 СтрокаДерева,
																									 Значение,
																									 УстанавливатьЗначениеКонтейнера);
	Если Не ЗначениеЗаполнено(СтрокаДерева.ВидКонтейнера) Тогда
		ВидыКонтейнераЗначения = ВидыКонтейнераЗначения();
		СтрокаРодитель = СтрокаДерева.ПолучитьРодителя();
		Если СтрокаРодитель <> Неопределено Тогда
			СтрокаДерева.ВидКонтейнера = ВидыКонтейнераЗначения.ВычислитьПоРодительскойСтроке;
		Иначе
			СтрокаДерева.ЗначениеЕстьОшибка = Истина;
			СтрокаДерева.ЗначениеОписаниеОшибки = "Не удалось установить вычисленное значение в реквизит формы.";
			
//			СтрокаДерева.ЗначениеТипЗначенияПредставление = "Ошибка установки значения";
//			СтрокаДерева.ЗначениеПредставление = "Не удалось установить вычисленное значение в реквизит формы.";
			Если Очистить Тогда
				СтрокаДерева.ПолучитьЭлементы().Очистить();
			КонецЕсли;

		КонецЕсли;
	КонецЕсли;
	Если СтрокаДерева.ЗначениеТипЗначения = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Если СтрокаДерева.ЗначениеТипЗначения.Свойства.Количество()>0 Тогда
		СтрокаДерева.ПолучитьЭлементы().Добавить();
	КонецЕсли;
	
	
КонецПроцедуры

#КонецОбласти
